﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Diagnostics;
using System.Xml;
using System.Xml.Serialization;
namespace AccessExport
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// n00_表名_日期_001
        /// </summary>
        const string format = "n00_mc_id_{0}_{1}_001";

        /// <summary>
        /// 数据文件名 分隔符 数据文件的大小（以k为单位）分隔符 数据总条数 分隔符 数据日期（年月）分隔符 文件的生成时间
        /// </summary>
        const string formatVal = "{0}`{1}`{2}`{3}'{4}";
        const string config = "tables.config";

        /// <summary>
        /// 文件编码
        /// </summary>
        static readonly Encoding encoding = Encoding.UTF8;

        public MainForm()
        {
            InitializeComponent();
        }

        private void btnDatabase_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofdDb = new OpenFileDialog();
            ofdDb.Title = "请选择数据库文件";
            ofdDb.Filter = "Access文件|*.accdb;*.mdb";
            if (ofdDb.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                tbDatabase.Text = ofdDb.FileName;
            }
        }

        private void btnOutput_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbdOutput = new FolderBrowserDialog();
            fbdOutput.Description = "请选择输出目录";
            if (fbdOutput.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                tbOutput.Text = fbdOutput.SelectedPath;
            }
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            string configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, config);

            string output = tbOutput.Text;
            string dbPath = tbDatabase.Text;
            string columnSplit = tbColumnSpliter.Text;
            string rowSplit = tbRowSpliter.Text;

            if (string.IsNullOrWhiteSpace(dbPath))
            {
                MessageBox.Show("请选择数据库文件！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (!File.Exists(dbPath))
            {
                MessageBox.Show("数据库文件不存在！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (string.IsNullOrWhiteSpace(output))
            {
                MessageBox.Show("请选择输出目录！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (string.IsNullOrWhiteSpace(columnSplit))
            {
                MessageBox.Show("请填写列分隔符！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (string.IsNullOrEmpty(rowSplit))
            {
                rowSplit = "\r\n";
            }
            if (!Directory.Exists(output))
            {
                Directory.CreateDirectory(output);
            }
            OleDbConnectionStringBuilder builder = new OleDbConnectionStringBuilder();
            builder.DataSource = dbPath;
            builder.Provider = "Microsoft.ACE.OLEDB.12.0";
            OleDbConnection conn = new OleDbConnection(builder.ConnectionString);
            conn.Open();
            Config[] configs = null;
            bool isConfig = true;
            var tables = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new string[] { null, null, null, "TABLE" });
            if (!File.Exists(configFile))
            {
                if (MessageBox.Show(string.Format("程序运行目录没有找到配置文件: ”{0}“\n\n是否使用默认顺序获取所有表的数据？", config), "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
                {
                    return;
                }

                configs = new Config[tables.Rows.Count];
                for (int i = 0; i < tables.Rows.Count; i++)
                {
                    configs[i] = new Config();
                    configs[i].Table = string.Format("[{0}]", tables.Rows[i]["TABLE_NAME"].ToString());
                    var columns = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new string[] { null, null, configs[i].Table });
                    configs[i].Columns = new string[columns.Rows.Count];
                    for (int j = 0; j < columns.Rows.Count; j++)
                    {
                        configs[i].Columns[j] = string.Format("[{0}]", columns.Rows[j]["COLUMN_NAME"].ToString());
                    }
                }
                isConfig = false;
            }
            else
            {
                configs = (Config[])Deserialize(configFile, typeof(Config[]));
            }

            string dateString = DateTime.Now.ToString("yyyyMMdd");

            for (int i = 0; i < configs.Length; i++)
            {
                try
                {
                    string tableName = configs[i].Table.ToLower();
                    var cmd = conn.CreateCommand();
                    if (isConfig)
                    {
                        if (tables.Select(string.Format("TABLE_NAME='{0}'", tableName)).Length == 0)
                        {
                            continue;
                        }
                    }

                    string fileName = string.Format(format, tableName, dateString);

                    string dataFile = fileName + ".dat";
                    string valFile = fileName + ".val";
                    string[] vals = new string[5];
                    StreamWriter writer = new StreamWriter(Path.Combine(output, dataFile), false, encoding);
                    cmd.CommandText = string.Format("SELECT {0} FROM [{1}]", string.Join(",", configs[i].Columns), tableName);
                    int recordCount = 0;
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            object[] values = new object[reader.FieldCount];
                            reader.GetValues(values);
                            string[] stringValues = new string[reader.FieldCount];
                            for (int j = 0; j < values.Length; j++)
                            {
                                stringValues[j] = values[j].ToString().Replace("\r\n", " ");
                            }

                            writer.Write(string.Join(columnSplit, stringValues));
                            writer.Write(rowSplit);
                            recordCount++;
                        }
                    }
                    writer.Flush();
                    var byteCount = writer.BaseStream.Length;
                    writer.Dispose();
                    vals[0] = dataFile;
                    vals[1] = byteCount.ToString();
                    vals[2] = recordCount.ToString();
                    vals[3] = DateTime.Now.ToString("yyyyMM");
                    vals[4] = DateTime.Now.ToString("yyyyMMddhhmmss");
                    //数据文件名 分隔符 数据文件的大小（以k为单位）分隔符 数据总条数 分隔符 数据日期（年月）分隔符 文件的生成时间
                    //n00_mc_base_class_20140403_001.dat`1`1`201404`20140403113024
                    File.WriteAllText(Path.Combine(output, valFile), string.Join(columnSplit, vals), encoding);
                    //Debug.WriteLine(tables.Rows[i]["TABLE_NAME"].ToString());
                }
                catch (Exception ex)
                {
                    MessageBox.Show("导出失败！\n\n" + ex.Message, "完成");
                }
            }
            conn.Close();
            MessageBox.Show("导出成功！", "完成");
        }

        #region XML序列化
        public static void Serialiaze(string filename, object obj)
        {
            XmlSerializer xs = new XmlSerializer(obj.GetType());
            Stream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            xs.Serialize(stream, obj);
            stream.Close();
            stream.Dispose();
        }
        #endregion

        #region XML反序列化
        public static object Deserialize(string filename, Type type)
        {
            if (File.Exists(filename))
            {
                using (StreamReader reader = new StreamReader(filename))
                {
                    XmlTextReader xmlReader = new XmlTextReader(reader);
                    // 处理空格
                    xmlReader.WhitespaceHandling = WhitespaceHandling.All;
                    XmlSerializer xs = new XmlSerializer(type);
                    return xs.Deserialize(xmlReader);
                }
            }
            else
            {
                return null;
            }
        }
        public static object DeserializeXMLData(string data, Type type)
        {
            try
            {
                XmlSerializer mySerializer = new XmlSerializer(type);
                StreamReader mem2 = new StreamReader(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(data)), System.Text.Encoding.UTF8);
                return mySerializer.Deserialize(mem2);
            }
            catch
            {
                return null;
            }
        }
        #endregion
    }
}
